package com.lwj.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

public final class CustomReflectUtil {

    private static final String getStr = "get";
    private static final String setStr = "set";
    private static final String serialVersionUIDStr = "serialVersionUID";

    private CustomReflectUtil() {

    }

    /**
     * 执行Bean中的get方法
     * @param object bean对象
     * @param propertyName bean中属性名
     * @return bean属性值
     */
    public static Object invokeGetterMethod(Object object, String propertyName) {

        String methodName = getStr + StringUtils.capitalize(propertyName);
        try {

            Method getMethod = ReflectionUtils.findMethod(object.getClass(), methodName);
            return ReflectionUtils.invokeMethod(getMethod, object);
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * 执行Bean中的get方法
     * @param object bean对象
     * @return bean属性值
     */
    public static Object invokeMethod(Object object, String methodName) {
        try {
            Method getMethod = ReflectionUtils.findMethod(object.getClass(), methodName);
            return ReflectionUtils.invokeMethod(getMethod, object);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 执行Bean中的set方法
     * @param object bean对象
     * @param methodName bean中属性名
     * @param propertyValue bean中属性值
     */
    public static void invokeMethod(Object object, String methodName, Object propertyValue) {

        if (propertyValue == null) {
            return;
        }
        // 获取属性值的类型
        Class<?> valueType = propertyValue.getClass();
        Method setMethod = ReflectionUtils.findMethod(object.getClass(), methodName, valueType);
        ReflectionUtils.invokeMethod(setMethod, object, propertyValue);
    }
    /**
     * 执行Bean中的set方法
     * @param object bean对象
     * @param propertyName bean中属性名
     * @param propertyValue bean中属性值
     */
    public static void invokeSetterMethod(Object object, String propertyName, Object propertyValue) {

        if (propertyValue == null) {
            return;
        }

        // 获取属性值的类型
        Class<?> valueType = propertyValue.getClass();
        String methodName = setStr + StringUtils.capitalize(propertyName);

        Method setMethod = ReflectionUtils.findMethod(object.getClass(), methodName, valueType);
        ReflectionUtils.invokeMethod(setMethod, object, propertyValue);
    }

    /**
     * 获取bean中的所有属性
     * @param clazz bean.class
     * @return 属性List
     */
    public static List<Field> getFields(Class<?> clazz) {

        List<Field> fieldList = new ArrayList<Field>();
        getBeanFields(clazz, fieldList);
        return fieldList;
    }

    /**
     * 将Bean转换为HashMap结构 HashMap<属性名, 属性值>
     * @param t Bean对象
     * @param <T> Bean类型
     * @return HashMap结构
     */
    public static <T> HashMap<String, Object> getMap(T t) {

        HashMap<String, Object> hashMap = new HashMap<String, Object>();
        if (t == null) {
            return hashMap;
        }

        Class<?> clazz = t.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field filed : fields) {

            // serialVersionUID并不会封装到hashMap中
            if (serialVersionUIDStr.equals(filed.getName())) {
                continue;
            }

            hashMap.put(filed.getName(), invokeGetterMethod(t, filed.getName()));
        }

        return hashMap;
    }

    /**
     * 将BeanList转换为LinkedList<LinkedHashMap<属性名, 属性值>>
     * @param tList BeanList
     * @param <T> Bean类型
     * @return LinkedList<LinkedHashMap<String, Object>>
     */
    public static <T> LinkedList<LinkedHashMap<String, Object>> getLinkHashMapList(List<T> tList) {

        LinkedList<LinkedHashMap<String, Object>> linkedHashMapList = new LinkedList<LinkedHashMap<String, Object>>();
        if (tList == null || tList.size() == 0) {
            return linkedHashMapList;
        }

        Class<?> clazz = tList.get(0).getClass();
        List<Field> fields = new ArrayList<Field>();
        fields = getBeanFields(clazz, fields);

        LinkedHashMap<String, Object> linkedHashMap = null;
        for (T t : tList) {

            linkedHashMap = new LinkedHashMap<>();

            for (Field f : fields) {

                linkedHashMap.put(f.getName(), invokeGetterMethod(t, f.getName()));
            }
            linkedHashMapList.add(linkedHashMap);
        }

        return linkedHashMapList;
    }

    /**
     * 获取Bean中的所有属性对象
     * @param clazz Bean.class
     * @param fieldList 属性List
     * @return 属性List
     */
    private static List<Field> getBeanFields(Class<?> clazz, List<Field> fieldList) {

        Field[] classField = clazz.getDeclaredFields();
        Collections.addAll(fieldList, classField);

        // 如果还有父类存在的话,递归获取父类中的属性
        if (clazz.getSuperclass() != null) {
            Class<?> clsSup = clazz.getSuperclass();
            fieldList = getBeanFields(clsSup, fieldList);
        }
        return fieldList;
    }

    /**
     * 判断属性是否存在
     * @param object Bean对象
     * @param fieldName 属性名
     * @return 存在:true 不存在false
     */
    public static boolean existsField(Object object, String fieldName) {

        try {
            return object.getClass().getDeclaredField(fieldName) != null;
        } catch (NoSuchFieldException e) {
            return false;
        }
    }


}

